<?php declare(strict_types=1);
/**
 * @author      xianganyall <xianganyall@gmail.com>
 * @copyright   2023-2025 owner
 **/

namespace Srv\Libs\Pools;

use Srv\Libs\Common\CommJson;
use Srv\Libs\ConfModel\CacheConf;
use Srv\Libs\Exception\PoolItemException;
use Srv\Libs\Exception\PoolItemRedisException;
use Srv\Libs\Exception\RedisConnectException;
use Srv\Libs\Exception\RedisPoolException;
use Srv\Libs\Frame\Logs;
use Srv\Libs\Storage\DataRedis;

final class PoolCache extends PoolAbstract
{
    private ?CacheConf $CacheConf               = null;         // CacheConf

    /**
     * PoolCache constructor.
     * @param CacheConf $CacheConf
     * @throws RedisPoolException
     * __construct
     */
    final public function __construct(CacheConf $CacheConf)
    {
        $this->checkTime        = max($CacheConf->getPoolCheckTime(), 0);
        $this->recycleTime      = $CacheConf->getPoolRecycleTime();
        $this->waitMilliTime    = $CacheConf->getPoolWaitMilliTime();
        $this->startNum         = $CacheConf->getPoolStartNum();
        $this->minNum           = $CacheConf->getPoolMinNum();
        $this->maxNum           = $CacheConf->getPoolMaxNum();
        $this->CacheConf        = $CacheConf;
        $this->CacheConf->setKeepalive(false);     // 使用短连接
        if($this->minNum > $this->startNum || $this->startNum > $this->maxNum || $this->startNum < 1 || $this->minNum < 1 || $this->maxNum < 1){
            throw new RedisPoolException(CommJson::encodeArray(['msg' => 'Configure failed', 'groupName' => $this->CacheConf->getGroupName(), 'startNum' => $this->startNum, 'minNum' => $this->minNum, 'maxNum' => $this->maxNum]), -1);
        }
        parent::__construct(Pool::getIndexKey(Pool::POOL_CACHE, $this->CacheConf->getGroupName()));
    }

    /**
     * __destruct
     */
    final public function __destruct()
    {
        parent::__destruct();
    }

    /**
     * @param bool $isUse
     * @return bool|PoolItem
     * getNewPoolItem
     */
    final protected function getNewPoolItem(bool $isUse)
    {
        $itemId         = $this->getItemId();
        try{
            $DataRedis  = new DataRedis($this->CacheConf, 'REDIS_P_'.$itemId);
            $DataRedis->connect();
        }catch(RedisConnectException $RedisConnectException){
            Logs::exception($RedisConnectException->getMessageLog(), $RedisConnectException->getLine(), $RedisConnectException->getFile(), '');
            return false;
        }
        $PoolItem       = new PoolItem($DataRedis, $itemId);
        if($isUse) $PoolItem->used();
        $DataRedis->initPool($this, $PoolItem);
        return $PoolItem;
    }

    /**
     * @param PoolItem $PoolItem
     * @return bool
     * recycleResult
     */
    final protected function recycleResult(PoolItem $PoolItem):bool
    {
        $DataRedis          = $PoolItem->getPoolObject();
        if($DataRedis instanceof DataRedis && !$PoolItem->isUse()){
            return $DataRedis->close();
        }
        return false;
    }

    /**
     * @param PoolItem $PoolItem
     * @return bool
     * checkResult
     */
    final protected function checkResult(PoolItem $PoolItem):bool
    {
        $DataRedis          = $PoolItem->getPoolObject();
        if($DataRedis instanceof DataRedis && !$PoolItem->isUse()){
            return $DataRedis->isConnected();
        }
        return false;
    }

    /**
     * @param bool $isAutoFree
     * @return DataRedis
     * @throws PoolItemRedisException
     * getDataRedis
     */
    final public function getDataRedis(bool $isAutoFree):DataRedis
    {
        try{
            $DataRedis      = $this->getPoolItem($isAutoFree)->getPoolObject();
            if($DataRedis instanceof DataRedis) return $DataRedis;
        }catch(PoolItemException $PoolItemException){
            Logs::exception($PoolItemException->getMessageLog(), $PoolItemException->getLine(), $PoolItemException->getFile(), '');
        }
        throw new PoolItemRedisException(CommJson::encodeArray(['msg' => 'DataRedis get failed']), -1);
    }
}